feat(selfhost): support per-repo model overrides for ollama/openai/anthropic providers - #3965
Conversation
…thropic providers review.ai_model's per-repo reviewer model override only worked for the claude-code/codex CLI subscription providers. createOpenAiCompatibleAi and createAnthropicAi bound their model ONCE at buildProvider() construction time from a global env var, with no per-call override parameter at all -- so an operator running ollama/openai/openai- compatible/anthropic across multiple repos had no way to set a stronger/cheaper model per repo the way claude-code/codex operators already could; the config field was silently ignored. Extend SelfHostAiModelConfig (packages/gittensory-engine) and AiRunOptions with ollamaModel/openaiModel/openaiCompatibleModel/ anthropicModel, thread them through the full chain (focus-manifest parser -> processors.ts -> GittensoryAiReviewInput -> AiRunCorrelation -> runWorkersOpinion's ai.run() call), and read them per-call inside createOpenAiCompatibleAi/createAnthropicAi's own run() -- mirroring exactly how claudeModel/codexModel already work, at the same repo- override > global-env-var > hardcoded-default priority. Also extends the AI-review cache fingerprint (bumped v3->v4) so changing one of these repo overrides correctly invalidates a previously-cached review. Closes #3902
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | 1e2f0b8 | Commit Preview URL Branch Preview URL |
Jul 07 2026, 08:02 AM |
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-07 08:06:06 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 7 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3965 +/- ##
==========================================
- Coverage 93.68% 93.67% -0.01%
==========================================
Files 373 373
Lines 34895 34919 +24
Branches 12768 12791 +23
==========================================
+ Hits 32692 32712 +20
Misses 1584 1584
- Partials 619 623 +4
🚀 New features to boost your workflow:
|
Summary
review.ai_modelin.gittensory.yml) was wired end-to-end only for the two CLI-subscription providers (claude-code/codex).createOpenAiCompatibleAi(ollama/openai/openai-compatible) andcreateAnthropicAibound their model ONCE atbuildProvider()construction time from a global env var, with no per-call override parameter at all.review.ai_model.ollama_model(etc.) config entry was silently ignored, with no warning, whenever the active provider wasn't claude-code/codex.SelfHostAiModelConfig(packages/gittensory-engine/src/focus-manifest.ts— this type was extracted into the shared engine package; the miner package doesn't consume it, so this is gittensory-review-only) andAiRunOptions(src/selfhost/ai.ts) withollamaModel/openaiModel/openaiCompatibleModel/anthropicModel, threaded through the full chain: focus-manifest parser →processors.ts→GittensoryAiReviewInput→AiRunCorrelation→runWorkersOpinion'sai.run()call → read per-call insidecreateOpenAiCompatibleAi/createAnthropicAi's own.run()— mirroring exactly howclaudeModel/codexModelalready work, at the same repo-override > global-env-var > hardcoded-default priority.src/review/ai-review-cache-input.ts, version bumped v3→v4 following the file's own established precedent for adding a hashed field) so changing one of these new per-repo overrides correctly invalidates a previously-cached review instead of replaying a decision made under a different model.claudeEffort/codexEfforthave no equivalent for these HTTP-API providers (no existing effort-shaping mechanism to override — inventing one is a separate, larger feature).config/examples/gittensory.full.yml's commentedai_model:example block un-updated: that file sits at 65,478/65,536 bytes againstMAX_FOCUS_MANIFEST_BYTES, ~58 bytes of margin — nowhere near enough room for 4 new documented keys without trimming unrelated comment text elsewhere in a 65KB shared file. Noting this explicitly rather than silently leaving the example incomplete (a known, pre-existing byte-budget fragility, also flagged in feat(regate-sweep): add opt-in oldest-first ordering mode to selectRegateCandidates #3867 earlier).Found via a fresh performance/scalability/accuracy hardening audit of the self-host ORB stack. Tracked under #1667.
Scope
packages/gittensory-engine/src/focus-manifest.ts— type, empty-config, parser, presence-check, serializationsrc/selfhost/ai.ts—AiRunOptions,createOpenAiCompatibleAi(+ newproviderNamefield),createAnthropicAi,buildProvidersrc/services/ai-review.ts—GittensoryAiReviewInput,AiRunCorrelation, construction + spread sitessrc/queue/processors.ts— forward the 4 new fields from the resolved manifestsrc/review/ai-review-cache-input.ts— fingerprint fields + version bump v3→v4focus-manifest.test.ts(parser, all 8 knobs + each new one individually with round-trip),selfhost-ai.test.ts(per-provider override priority +buildProviderend-to-end wiring),ai-review-cache-input.test.ts(fingerprint changes per new field); fixed 2 pre-existing test files whose fixtures/assertions needed updating for the stricter type / bumped cache versionValidation
npm run typechecknpm run test:coverage(full unsharded) — 561 files / 11120 tests passed; changed lines in every touchedsrc/**file fully covered perlcov.info(cross-checked against diff hunks — zero overlap with pre-existing uncovered lines)git diff --checkcleanSafety
.gittensory.ymlai_model.*set) are byte-identical to today: same global-env-var-then-hardcoded-default resolution as before this existed. No secrets; no new credential paths (only the model NAME can be redirected, never the API key/base URL, matching the existing claude/codex override's own scope).Closes #3902